
#include "FontsetPanelExt.h"
#include "PreviewWindow.h"
#include "ConfigDialog.h"
#include "FontDefinition.h"
#include "FontsetNotebook.h"
#include "wx/fontenum.h"
#include "wx/dir.h"

#include "ft2build.h"
#include FT_FREETYPE_H

#include <vector>
#include <string>

#include "tinyxml/tinyxml.h"

FontsetPanelExt::FontsetPanelExt( const wxString& name, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style )
    : FontsetPanel( parent, id, pos, size, style )
{
    mFontsetName->SetValue( name );

    FontMap& fontMap = FontMap::GetInstance();

    FontMap::ConstIterator mapIter = fontMap.Begin();
    for ( mapIter; mapIter != fontMap.End(); mapIter++ )
    {
        mFontName->Append( mapIter->first );

    }
    mFontName->SetSelection( 0 );

    // Fill in the initial font definition data
    mFontDef.mFontName          = mFontName->GetValue();
    mFontDef.mIsBold            = mFontBold->IsChecked();
    mFontDef.mIsUnderline       = mFontUnderline->IsChecked();
    mFontDef.mIsItalic          = mFontItalic->IsChecked();
    mFontDef.mFontHeight        = mFontHeight->GetValue();
    mFontDef.mFontWidth         = mFontWidth->GetValue();
    mFontDef.mStartCharacter    = mStartCharacter->GetValue();
    mFontDef.mImageWidth        = atoi( mImageWidth->GetString( mImageWidth->GetSelection() ).ToAscii() );
    mFontDef.mImageHeight       = atoi( mImageHeight->GetString( mImageHeight->GetSelection() ).ToAscii() );
    mFontDef.mCellWidth         = mCellWidth->GetValue();
    mFontDef.mCellHeight        = mCellHeight->GetValue();
    mFontDef.mAntiAliasMode     = FontDefinition::AntiAliasMode( mAntiAliasMode->GetSelection() );

    mFontDef.mFontFileName      = fontMap.GetFileName( mFontDef.mFontName, mFontDef.mIsBold, mFontDef.mIsItalic );

    UpdatePreview();
}

FontsetPanelExt::~FontsetPanelExt(void)
{
}

//LoadPage
void FontsetPanelExt::LoadPage( TiXmlElement* root )
{
    assert( root );
    TiXmlHandle pageHandle( root );

    // Read the font name:
    TiXmlNode* nameNode = pageHandle.FirstChild( "fontName" ).Node();
    if ( nameNode && nameNode->FirstChild() )
    {
        StringUtil::String fontName = nameNode->FirstChild()->Value();
        mFontDef.mFontName = fontName;

        // Find this name in the list and select it:
        mFontName->Select( mFontName->FindString( fontName.c_str() ) );        
    }

    // Modifier flags
    TiXmlNode* node = pageHandle.FirstChild( "bold" ).Node();
    StringUtil::String text;
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mIsBold = atoi( text.c_str() );
        mFontBold->SetValue( mFontDef.mIsBold );
    }
    node = pageHandle.FirstChild( "underline" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mIsUnderline = atoi( text.c_str() );
        mFontUnderline->SetValue( mFontDef.mIsUnderline );
    }
    node = pageHandle.FirstChild( "italic" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mIsItalic = atoi( text.c_str() );
        mFontItalic->SetValue( mFontDef.mIsItalic );
    }

    // Font width
    node = pageHandle.FirstChild( "fontWidth" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mFontWidth = atoi( text.c_str() );
        mFontWidth->SetValue( mFontDef.mFontWidth );
    }

    // Font height
    node = pageHandle.FirstChild( "fontHeight" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mFontHeight = atoi( text.c_str() );
        mFontHeight->SetValue( mFontDef.mFontHeight );
    }

    // Start character
    node = pageHandle.FirstChild( "startCharacter" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mStartCharacter = atoi( text.c_str() );
        mStartCharacter->SetValue( mFontDef.mStartCharacter );
    }

    // Bitmap width
    node = pageHandle.FirstChild( "bitmapWidth" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mImageWidth = atoi( text.c_str() );
        mImageWidth->Select( mImageWidth->FindString( text.c_str() ) );
    }

    // Bitmap height
    node = pageHandle.FirstChild( "bitmapHeight" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mImageHeight = atoi( text.c_str() );
        mImageHeight->Select( mImageHeight->FindString( text.c_str() ) );
    }

    // Cell width
    node = pageHandle.FirstChild( "cellWidth" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mCellWidth = atoi( text.c_str() );
        mCellWidth->SetValue( mFontDef.mCellWidth );
    }

    // Cell height
    node = pageHandle.FirstChild( "cellHeight" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mCellHeight = atoi( text.c_str() );
        mCellHeight->SetValue( mFontDef.mCellHeight );
    }

    // Anti-alias mode
    node = pageHandle.FirstChild( "antialias" ).Node();
    if ( node && node->FirstChild() )
    {
        text = node->FirstChild()->Value();
        mFontDef.mAntiAliasMode = ( text == "Normal" ) ? FontDefinition::Normal : FontDefinition::None;
        mAntiAliasMode->Select( mFontDef.mAntiAliasMode );
    }

    Modify( false );

    // Update the preview:
    UpdatePreview();
}

void FontsetPanelExt::OnCharFontsetName( wxKeyEvent& event )
{
    FontsetPanel::OnCharFontsetName( event );

    //wxString name = mFontsetName->GetValue();

    //// Get the parent (note that we are assuming the parent is a wxAuiNotebook!!!)
    ////FontsetNotebook* parent = static_cast< FontsetNotebook* >( GetParent() );
    //FontsetNotebook* parent = wxDynamicCast( GetParent(), FontsetNotebook );
    //int sel = parent->GetSelection();
    //if ( sel >= 0 && sel < parent->GetPageCount() )
    //    parent->SetPageText( sel, name );
    //Modify( mFontsetName->IsModified() );
}

void FontsetPanelExt::OnKeyUpFontsetName( wxKeyEvent& event )
{
    FontsetPanel::OnKeyUpFontsetName( event );

    wxString name = mFontsetName->GetValue();

    // Get the parent (note that we are assuming the parent is a wxAuiNotebook!!!)
    //FontsetNotebook* parent = static_cast< FontsetNotebook* >( GetParent() );
    FontsetNotebook* parent = wxDynamicCast( GetParent(), FontsetNotebook );
    int sel = parent->GetSelection();
    if ( sel >= 0 && sel < parent->GetPageCount() )
        parent->SetPageText( sel, name );
    Modify( mFontsetName->IsModified() );
}

//void FontsetPanelExt::SetFontsetName( const StringUtil::String& name )
//{
//    mFontsetName->SetValue( name );
//}

void FontsetPanelExt::OnKillFocusFontsetName( wxFocusEvent& event )
{
    wxString name = mFontsetName->GetValue();

    // Get the parent (note that we are assuming the parent is a wxAuiNotebook!!!)
    //FontsetNotebook* parent = static_cast< FontsetNotebook* >( GetParent() );
    FontsetNotebook* parent = wxDynamicCast( GetParent(), FontsetNotebook );
    int sel = parent->GetSelection();
//    if ( sel >= 0 && sel < parent->GetPageCount() )
//        parent->SetPageText( sel, name );
    //Modify( mFontsetName->IsModified() );
}

void FontsetPanelExt::OnFontsetNameChanged( wxCommandEvent& event )
{
    wxString name = mFontsetName->GetValue();

    //// Get the parent (note that we are assuming the parent is a wxAuiNotebook!!!)
    ////FontsetNotebook* parent = static_cast< FontsetNotebook* >( GetParent() );
    //FontsetNotebook* parent = wxDynamicCast( GetParent(), FontsetNotebook );
    //int sel = parent->GetSelection();
    //if ( sel >= 0 && sel < parent->GetPageCount() )
    //    parent->SetPageText( sel, name );
    //Modify( mFontsetName->IsModified() );
}

void FontsetPanelExt::OnFontName( wxCommandEvent& event )
{
    StringUtil::String fontName = mFontName->GetValue();
    mFontDef.mFontName = fontName;
    //FontMap::ConstIterator mapIter = fontMap.Find( fontName );
    //if ( mapIter != fontMap.End() )
    //{
    //    mFontDef.mFontName = fontName;
    //    //mFontDef.mFontFileName = mapIter->second;
    //}
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnBold( wxCommandEvent& event )
{
    mFontDef.mIsBold = mFontBold->IsChecked();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnUnderline( wxCommandEvent& event )
{
    mFontDef.mIsUnderline = mFontUnderline->IsChecked();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnItalic( wxCommandEvent& event )
{
    mFontDef.mIsItalic = mFontItalic->IsChecked();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnFontHeightChanged( wxCommandEvent& event )
{
    mFontDef.mFontHeight        = mFontHeight->GetValue();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnFontWidthChanged( wxCommandEvent& event )
{
    mFontDef.mFontWidth         = mFontWidth->GetValue();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnStartCharacterChanged( wxCommandEvent& event )
{
    mFontDef.mStartCharacter    = mStartCharacter->GetValue();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnImageSizeChanged( wxCommandEvent& event )
{
    mFontDef.mImageWidth        = atoi( mImageWidth->GetString( mImageWidth->GetSelection() ).ToAscii() );
    mFontDef.mImageHeight       = atoi( mImageHeight->GetString( mImageHeight->GetSelection() ).ToAscii() );
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnCellHeightChanged( wxCommandEvent& event )
{
    mFontDef.mCellHeight        = mCellHeight->GetValue();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnCellWidthChanged( wxCommandEvent& event )
{
    mFontDef.mCellWidth         = mCellWidth->GetValue();
    Modify( true );
    UpdatePreview();
}

void FontsetPanelExt::OnAntiAlias( wxCommandEvent& event )
{
    mFontDef.mAntiAliasMode     = FontDefinition::AntiAliasMode( mAntiAliasMode->GetSelection() );
    Modify( true );
    UpdatePreview();
}

//Modify
void FontsetPanelExt::Modify( bool mod )
{
    mIsModified = mod;
}

//IsModified
bool FontsetPanelExt::IsModified() const
{
    return mIsModified;
}

//GetViewGridlines
bool FontsetPanelExt::GetViewGridlines() const
{
    FontsetNotebook* parent = wxDynamicCast( GetParent(), FontsetNotebook );
    if ( parent )
        return parent->GetViewGridlines();
    return false;
}

//GetViewWidths
bool FontsetPanelExt::GetViewWidths() const
{
    FontsetNotebook* parent = wxDynamicCast( GetParent(), FontsetNotebook );
    if ( parent )
        return parent->GetViewWidths();
    return false;
}

//UpdatePreview
void FontsetPanelExt::UpdatePreview()
{
    // Make sure we have the correct font file
    FontMap& fontMap = FontMap::GetInstance();
    mFontDef.mFontFileName = fontMap.GetFileName( mFontDef.mFontName, mFontDef.mIsBold, mFontDef.mIsItalic );

    mPreviewWindow->UpdateDisplay( mFontDef );
}

void FontsetPanelExt::SavePNG( TiXmlElement* root, const StringUtil::String& location ) const
{
    // Generate the PNG image:
    StringUtil::String imageFileName = StringUtil::String( mFontsetName->GetValue().ToAscii() ) + ".png";
    mPreviewWindow->SavePNG( location + imageFileName );

    // Save the fontset:
    TiXmlElement* node = new TiXmlElement( "identifier" );
    root->LinkEndChild( node );
    TiXmlText* text = new TiXmlText( mFontsetName->GetValue().ToAscii() );
    node->LinkEndChild( text );

    // Font name
    node = new TiXmlElement( "fontName" );
    root->LinkEndChild( node );
    text = new TiXmlText( mFontName->GetValue().ToAscii() );
    node->LinkEndChild( text );

    // Bold
    node = new TiXmlElement( "bold" );
    root->LinkEndChild( node );
    text = new TiXmlText( mFontBold->IsChecked() ? "1" : "0" );
    node->LinkEndChild( text );

    // Underline
    node = new TiXmlElement( "underline" );
    root->LinkEndChild( node );
    text = new TiXmlText( mFontUnderline->IsChecked() ? "1" : "0" );
    node->LinkEndChild( text );

    // Italic
    node = new TiXmlElement( "italic" );
    root->LinkEndChild( node );
    text = new TiXmlText( mFontItalic->IsChecked() ? "1" : "0" );
    node->LinkEndChild( text );

    // Font height
    node = new TiXmlElement( "fontHeight" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( mFontHeight->GetValue() ).c_str() );
    node->LinkEndChild( text );

    // Font width
    node = new TiXmlElement( "fontWidth" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( mFontWidth->GetValue() ).c_str() );
    node->LinkEndChild( text );

    // Start glyph
    node = new TiXmlElement( "startCharacter" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( mStartCharacter->GetValue() ).c_str() );
    node->LinkEndChild( text );

    // Width of the cells
    int cellWidth = mCellWidth->GetValue();
    node = new TiXmlElement( "cellWidth" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( cellWidth ).c_str() );
    node->LinkEndChild( text );

    // Height of the cells
    int cellHeight = mCellHeight->GetValue();
    node = new TiXmlElement( "cellHeight" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( cellHeight ).c_str() );
    node->LinkEndChild( text );

    // Bitmap image file name
    node = new TiXmlElement( "fontBitmap" );
    root->LinkEndChild( node );
    text = new TiXmlText( imageFileName.c_str() );
    node->LinkEndChild( text );

    // Width of the bitmap
    int bitmapWidth = atoi( mImageWidth->GetString( mImageWidth->GetSelection() ).ToAscii() );
    node = new TiXmlElement( "bitmapWidth" );
    root->LinkEndChild( node );
    text = new TiXmlText( mImageWidth->GetString( mImageWidth->GetSelection() ).ToAscii() );
    node->LinkEndChild( text );

    // Height of the bitmap
    int bitmapHeight = atoi( mImageHeight->GetString( mImageHeight->GetSelection() ).ToAscii() );
    node = new TiXmlElement( "bitmapHeight" ); 
    root->LinkEndChild( node );
    text = new TiXmlText( mImageHeight->GetString( mImageHeight->GetSelection() ).ToAscii() );
    node->LinkEndChild( text );

    // Antialias mode
    node = new TiXmlElement( "antialias" );
    root->LinkEndChild( node );
    text = new TiXmlText( mAntiAliasMode->GetString( mAntiAliasMode->GetSelection() ).ToAscii() );
    node->LinkEndChild( text );

    // Number of horizontal tiles in the bitmap
    int horzTiles = bitmapWidth / cellWidth;
    node = new TiXmlElement( "bitmapHorzTiles" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( horzTiles ).c_str() );
    node->LinkEndChild( text );

    // Number of vertical tiles in the bitmap
    int vertTiles = bitmapHeight / cellHeight;
    node = new TiXmlElement( "bitmapVertTiles" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( vertTiles ).c_str() );
    node->LinkEndChild( text );

    // Start glyph
    int startGlyph = mStartCharacter->GetValue();
    node = new TiXmlElement( "startGlyph" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( startGlyph ).c_str() );
    node->LinkEndChild( text );

    // Glyph count
    int glyphCount = horzTiles * vertTiles;
    node = new TiXmlElement( "glyphCount" );
    root->LinkEndChild( node );
    text = new TiXmlText( StringUtil::ToString( glyphCount ).c_str() );
    node->LinkEndChild( text );

    // Glyph list
    TiXmlElement* glyphListNode = new TiXmlElement( "glyphList" );
    root->LinkEndChild( glyphListNode );

    PreviewWindow::WidthsArrayType widthsArray;
    mPreviewWindow->GetGlyphWidths( &widthsArray );
    assert( widthsArray.size() == glyphCount );
    // Go over the glyphs and write each character's width
    for ( int curGlyph = startGlyph; curGlyph < startGlyph + glyphCount; curGlyph++ )
    {
        TiXmlElement* glyphNode = new TiXmlElement( "glyph" );
        glyphListNode->LinkEndChild( glyphNode );

        // Glyph index
        node = new TiXmlElement( "index" );
        glyphNode->LinkEndChild( node );
        text = new TiXmlText( StringUtil::ToString( curGlyph ).c_str() );
        node->LinkEndChild( text );

        // Glyph width
        node = new TiXmlElement( "width" );
        glyphNode->LinkEndChild( node );
        text = new TiXmlText( StringUtil::ToString( widthsArray[ curGlyph - startGlyph ] ).c_str() );
        node->LinkEndChild( text );
    }
}
